<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * @package    Libraries/Authentication
 * @author     Nick Eldridge <nick@neldridge.net>
 * @license    Mozilla Public License v1.1 <http://www.mozilla.org/MPL/MPL-1.1.html>
 */

class Authentication {



	public $user_id;
	
	
	public $user_table = 'users';
	public $hash_table = 'user_auth';
	
	public $uid_col = 'user_id';
	public $un_col = 'username';
	// Password hashing is md5(username.password.private_key)
	public $pw_col = 'password';
	public $email_col = 'email';
	public $hash_col = 'hash';
	
	public $private_key = 'hOGM\7T"d{y4;U%px~7*U\;>=BF5#HV2"P[eAJGXw.|a^t_SL(;Cw`?AYe:t\pL#u3gs>-zB249]I$E=B7LMZlE{uCH(;QWC}ems9o1cw)7i@}TmaWvWeM%ihlS+nu';
	
	
	
	
	private $duplicate_emails = FALSE; // True for allowing duplicate emails.
	private $email_required = TRUE; // 
	
	
	public $CI;
	


	function __construct ($params)
	{	
	
	
		log_message('debug', "Authentication Class Initialized");
		
		
		# This is to get the instance of the CodeIgniter instance, so 
		# we have access to the session / database class.
		$this->CI =& get_instance();
		

		

		# Set all the class variables.
		if (isset($params['user_table'])) 	$this->user_table 	= $params['user_table'];
	
		if (isset($params['uid_col'])) 		$this->uid_col 		= $params['uid_col'];
		if (isset($params['un_col'])) 		$this->un_col 		= $params['un_col'];
		if (isset($params['pw_col'])) 		$this->pw_col 		= $params['pw_col'];
		if (isset($params['email_col'])) 	$this->email_col 	= $params['email_col'];
	
		if (isset($params['hash_col'])) 	$this->hash_col 	= $params['hash_col'];
		if (isset($params['hash_table'])) 	$this->hash_table 	= $params['hash_table'];
		
		if (isset($params['duplicate_emails'])) $this->duplicate_emails	= $params['duplicate_emails'];
		if (isset($params['email_required'])) $this->email_required	= $params['email_required'];
		
		if (isset($params['private_key']))	$this->private_key	= $params['private_key'];
	
		
	}
	
	
	
	
	
	/**************************************************
	 *
	 * Login Function
	 * @description: Login user.
	 *
	 **************************************************/
	function login ( $username, $password ) 
	{

		
		// build query using active record class.
		
		$this->CI->db->select($this->uid_col.", lower(".$this->un_col.") AS username");
		
		$this->CI->db->where('lower('.$this->un_col.')', strtolower($username));
		
		$this->CI->db->where($this->pw_col,  $this->hash_password($username, $password));
		
		$result = $this->CI->db->get($this->user_table);
		
		
		//if the query fails
		if ( !$result )
		{
			log_message('error', 'Authentication Library, login failure. '.$this->CI->db->_error_message());
			return FALSE;
		}
		
		
		
		if ( $result->num_rows == 1 ) 
		{
			$row = $result->row();
			$un_col = $this->un_col;
			
			if (strtolower($username) == $row->username) 
			{
			
				$uid_col = $this->uid_col;
				$this->user_id = $row->$uid_col;
				

				$this->update_hash();
							
				return TRUE;			
			}
		
		} 
		
		// Login Failure
		return FALSE;
		
	
	}
	
	function update_hash() 
	{
	
		/// Update Session variables.
		$this->CI->session->set_userdata($this->uid_col, $this->user_id);
		$this->CI->session->set_userdata($this->hash_col, md5($this->user_id.$this->private_key));
				
				
		// Get some variables, for sanitization.
		$session_id = $this->CI->session->userdata('session_id');
		$user_id 	= $this->CI->session->userdata($this->uid_col);
		$hash 		= $this->CI->session->userdata($this->hash_col);
		
		// Delete any session currently entered from this browser.
		$this->CI->db->delete($this->hash_table, array('session_id' => $session_id)); 
		
		// Enter a new one.
		$data = array(
               'session_id'		=> $session_id,
               $this->uid_col	=> $user_id,
               $this->hash_col	=> $hash
            );

		$this->CI->db->insert($this->hash_table, $data); 

		
		
	}
	/**************************************************
	 *
	 * Logout Function
	 *
	 **************************************************/
	function logout ( ) 
	{
		$this->CI->session->unset_userdata(array($this->hash_col => '', $this->uid_col => ''));
		return TRUE;
	
	}

	/**************************************************
	 *
	 * Register Function
	 *
	 **************************************************/
	function hash_password($username, $password) 
	{
		$md5 = md5(strtolower(trim($username)).trim($password).$this->private_key);
		return $md5;
	
	}
	
	
	function register ( $data ) 
	{
	
		// this function should _only_ do the principal options
		// Username / Email / Password
		// The rest should be handled by a different function.
		
		foreach ( $data AS $k => $v ) 
		{
			switch ( strtolower($k) ) 
			{
				case $this->un_col:		$username 	= $v; break;
				case $this->email_col:	$email 		= $v; break;
				case $this->pw_col: 	$password 	= $v; break;
			
			}
		
		}
		
		
		
		// We need to check for duplicate Email / Username
		if ($this->email_required) 
		{
			if ($this->check_matches($this->email_col, $email) === TRUE) 
			{
				return FALSE; // duplicate email check
			}
		}
		if ($this->check_matches($this->un_col, $username) === TRUE)
		{
			return FALSE; // duplicate username check
		}
		
		$hashed_password = $this->hash_password($username, $password);
		
		
		
		$data = array(
               $this->un_col	=> $username,
               $this->pw_col 	=> $hashed_password
            );
            
        if (TRUE === $this->email_required && TRUE === empty($email))
		{
			return FALSE;		
		} 
		else if (FALSE === empty($email))
		{
			$data[$this->email_col]	= $email;
		}
		$this->CI->db->insert($this->user_table, $data); 
			
		
	
	}
	
	function update_password($user_id, $password) 
	{
	
		$username = $this->get_username($user_id);
		
		if (FALSE === $username) 
		{ 
			return FALSE; 
		}
		
		$data = array(
			$this->pw_col => $this->hash_password($username, $password)
		
		);
		
		$this->CI->db->where($this->uid_col, $user_id);
		$this->CI->db->update($this->user_table, $data);
		
		if ($this->CI->db->_error_number()) 
		{
			return FALSE;
		}
		
		return TRUE;
		
	}
	
	function check_matches ( $col, $val, $case_sensitive = FALSE  ) 
	{
		
		if ($this->duplicate_emails === TRUE && $col == $this->email_col) 
		{
			return FALSE;
		}
	
		$this->CI->db->select($col);
		
		
		if (TRUE == $case_sensitive) 
		{
			$this->CI->db->where($col,$val);
		} 
		else 
		{
			$this->CI->db->where('lower('.$col.')',strtolower($val));
		}
	
	
		$result = $this->CI->db->get($this->user_table);
		
		if ($result->num_rows == 0)
		{
			// Either there's nobody or there was an error.
			// Error checking apparently doesn't seem to be a high priority
			// For codeigniter so.. I guess no worries!
			return FALSE;
				
		} 
		return TRUE;
		
		
		
	
	
	}
	
	
	/**************************************************
	 *
	 *
	 *
	 **************************************************/
	 
	 function logged_in ( $data = array() ) 
	 {
	 	foreach ( $data AS $k => $v ) 
	 	{
	 		switch (strtolower($k)) 
	 		{
	 			case $this->uid_col: $user_id = $v; break;		
	 			case $this->un_col:	$username = $v; break;
	 			case $this->email_col: $email = $v; break;
	 		}
	 	
	 	}
	 	
	 	// If nothing is passed, let's see if we can get the user id
	 	// from the session, if we can't they aren't logged in anyway.
	 	if ( empty($user_id) === TRUE && empty($username) === TRUE && empty($email) === TRUE ) 
	 	{
	 		$user_id = $this->CI->session->userdata($this->uid_col);
	 		
	 	}
	 	// Get the session hash, if it's empty, they aren't logged in.
	 	$session_hash = $this->CI->session->userdata($this->hash_col);



	 	// We need to verify this user is logged in based on one of the variables passed
	 	if ( empty($user_id) === TRUE ) 
	 	{
	 		// We need to get the user_id from the email / username
	 		if ( empty($username) === FALSE ) 
	 		{
	 			// Attempt username first.
	 			$user_id = $this->get_userid(array($this->un_col=>$username));
	 		}	
	 		// If user_id is empty, we'll try the email if we have it.
	 		if ( empty($user_id) === TRUE && empty($email) === FALSE ) 
	 		{
	 			// Attempt email now.
	 			$user_id = $this->get_userid(array($this->email_col=>$email));
	 		}
	 	
	 	}
	 	
	 	
	 	// If either of these are empty, they aren't logged in.
	 	if (empty($session_hash) === TRUE || empty($user_id) === TRUE) 
	 	{
	 		return FALSE;
	 	}
	 	
	 	// We've passed the initial checks, let's see if we can get the exact information we have against the database
	 	// If we're able, they are logged in.
	 	
	 	$this->CI->db->select($this->uid_col.' AS result');
	 	$this->CI->db->where($this->hash_col, $session_hash);
	 	$this->CI->db->where($this->uid_col, $user_id);
	 	
	 	$result = $this->CI->db->get($this->hash_table);
	 	
	 	if ($result->num_rows == 0) 
	 	{
	 		return FALSE;
	 	
	 	}
	 	$r = $result->row();
	 	
	 	if ($r->result == $user_id) 
	 	{
	 		return TRUE;
	 	}
	 	
	 	return FALSE;
	 }
	
	function get_userid( $data ) 
	{
	
	
		if (!is_array($data)) $data = array($data);
		
		foreach ( $data AS $k => $v ) 
		{
		
			switch(strtolower($k)) 
			{
		 		case strtolower($this->un_col): 
		 		
		 			$this->CI->db->select($this->uid_col);
		 			$this->CI->db->where( $this->un_col, $v);
		 			
		 			$results = $this->CI->db->get($this->user_table);
		 			
		 			if ($results->num_rows == 0) 
		 			{
		 				continue;
		 			} 
		 			else 
		 			{
		 				$r = $results->row();
		 				return $r->{$this->uid_col};
		 			}
		 			
		 			break;		
				
				case strtolower($this->email_col): 
					$this->CI->db->select($this->uid_col);
		 			$this->CI->db->where( $this->email_col, $v);
		 			$results = $this->CI->db->get($this->user_table);
		 			
		 			if ($results->num_rows == 0) 
		 			{
		 				continue;
		 			} 
		 			else 
		 			{
		 				$r = $results->row();
		 				$uid_col = $this->uid_col;
		 				return $r->$uid_col;
		 			}
				
					break;
					
				case 'session':
				default:
				
					$user_id = $this->CI->session->userdata($this->uid_col);
					
					if (empty($user_id)===TRUE)
					{				
						return FALSE;
					}
					
					$logged_in = $this->logged_in(array($this->uid_col => $user_id));
					if ($logged_in === TRUE) 
					{
						return $user_id;
					}
					return FALSE;					
					break;
					
			}
		}
		
		// If we've gotten this far, it failed.
		return FALSE;
	}
	
	function get_username ( $user_id ) 
	{
		$this->CI->db->select($this->un_col);
		$this->CI->db->where($this->uid_col, $user_id);
		$result = $this->CI->db->get($this->user_table);
		
		if ($result->num_rows == 0) 
		{
			return FALSE;
		
		} 
		$r = $result->row_array();
		return $r[$this->un_col];
	
	
	}
	
	
}


/* End of file Authentication.php */
/* Location: ./system/libraries/Authentication.php */
